package database

import (
	"strings"

	"gitee.com/sansaniot/ssiot-core/logger"
	"gorm.io/gorm"

	"ssdevice/common/utils"
	"ssdevice/internal/device/models"
)

func PartitionTb(db *gorm.DB, tableName string) {
	scan := map[string]interface{}{}
	if err := db.Raw("SELECT relkind FROM pg_class WHERE relname = ?", tableName).Scan(&scan).Error; err != nil {
		logger.Error(err)
		return
	}
	if len(scan) == 0 {
		return
	}
	// 已经是分区表
	if scan["relkind"] == "p" {
		return
	}
	logger.Info("【开始构建主分区表, 请耐心等待...】")
	switch tableName {
	case models.SysHistorySensor{}.TableName():
		sql1 := `CREATE TABLE "` + tableName + `_systmp" (
			  "id" int8 NOT NULL DEFAULT nextval('sys_history_sensor_id_seq'::regclass),
			  "dev_sn" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
			  "key" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
			  "value" text COLLATE "pg_catalog"."default",
			  "update_time" timestamptz(6) NOT NULL
			) partition by list("dev_sn")`
		if err := db.Raw(sql1).Scan(&scan).Error; err != nil {
			logger.Error(err)
			return
		}
	}
	logger.Info("【" + tableName + "备份为" + tableName + "_sysbackup】")
	sql2 := `alter table ` + tableName + ` rename to ` + tableName + `_sysbackup`
	if err := db.Raw(sql2).Scan(&scan).Error; err != nil {
		logger.Error(err)
		return
	}
	logger.Info("【" + tableName + "_systmp分区表重命名为" + tableName + "】")
	sql3 := `alter table ` + tableName + `_systmp rename to ` + tableName
	if err := db.Raw(sql3).Scan(&scan).Error; err != nil {
		logger.Error(err)
		return
	}
	// 必需同步
	logger.Info("【开始构建子分区表, 请耐心等待...】")
	switch tableName {
	case models.SysHistorySensor{}.TableName():
		partitionHisSensor(db, tableName)
	}
	// 此处可以异步进行
	logger.Info("【开始异步进行数据迁移...】")
	go func() {
		sql5 := `insert into ` + tableName + ` select * from ` + tableName + `_sysbackup`
		if err := db.Raw(sql5).Scan(&scan).Error; err != nil {
			logger.Error(err)
			return
		}
	}()
	logger.Info("【分区表构建完成.】")
}

func partitionHisSensor(db *gorm.DB, tableName string) {
	scan := map[string]interface{}{}
	snRs := make([]map[string]interface{}, 0)
	sql4 := `select dev_sn from ` + tableName + `_sysbackup GROUP BY dev_sn`
	if err := db.Raw(sql4).Scan(&snRs).Error; err != nil {
		logger.Error(err)
		return
	}
	for _, m := range snRs {
		sn := utils.GetStringValueFiled(m, "dev_sn")
		snn := strings.ReplaceAll(strings.ReplaceAll(strings.ToLower(sn), "-", "_"), " ", "_")
		if err := db.Raw("create table if not EXISTS " + tableName + "_" + snn + " partition of " + tableName + " for values in ('" + sn + "') ").Scan(&scan).Error; err != nil {
			logger.Error(err)
			return
		}
		db.Raw("drop index if EXISTS idx_" + tableName + "_" + snn + "_key_time").Scan(&scan)
		cidx := `CREATE INDEX "idx_` + tableName + `_` + snn + `_key_time" ON "` + tableName + `_` + snn + `" USING btree (
					"key" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
					"update_time" "pg_catalog"."timestamptz_ops" ASC NULLS LAST
				);`
		if err := db.Raw(cidx).Scan(&scan).Error; err != nil {
			logger.Error(err)
			return
		}
	}
}
